<!--
 * @name: 
 * @Author: JiaYing
 * @LastEditors: JiaYing
 * @Date: 2022-08-21 17:24:48
 * @LastEditTime: 2022-08-23 15:55:39
 * @Description: 
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>浅拷贝和深拷贝</title>
  </head>
  <body></body>
</html>

<script>
  // 更多细节实现可以参考开源Lodash的深度克隆

  function isType(value, type) {
    type = type ? type : "";
    var toString = Object.prototype.toString;
    return (
      toString.call(value).toLowerCase() === `[object ${type.toLowerCase()}]`
    );
  }

  function clone(obj, deep) {
    function _cloneObject(obj) {
      let ret = {};
      ret.__proto__ = obj.__proto__;
      for (let key in obj) {
        if (isType(obj[key], "object") && deep) {
          ret[key] = _(obj[key]);
        } else {
          ret[key] = obj[key];
        }
      }
      return ret;
    }

    function _cloneFunction(fn) {
      return new Function("return " + fn.toString())();
    }

    function _cloneArray(arr) {
      let ret = [];
      for (let idx in arr) {
        if (isType(arr[idx], "array")) {
          ret[idx] = _cloneArray(arr);
        } else {
          ret[idx] = _(arr[idx]);
        }
      }
      return ret;
    }

    function _(obj) {
      let ret = {};
      for (let key in obj) {
        if (isType(obj[key], "array")) {
          ret[key] = _cloneArray(obj[key]);
        } else if (isType(obj[key], "function")) {
          ret[key] = _cloneFunction(obj[key]);
        } else if (isType(obj[key], "object")) {
          ret[key] = _cloneObject(obj[key]);
        } else {
          ret[key] = obj[key];
        }
      }
      return ret;
    }

    function run() {
      return deep ? _(obj) : _cloneObject(obj);
    }

    return run(obj);
  }

  function User(name) {
    this.name = name;
  }

  var o = {
    a: 1,
    b: "2",
    c: {},
    d: [1, 2, 3],
    e: {
      f: 1,
    },
    g: new User("tony"),
    h: function say() {
      console.log(this.g.name + "say hi");
    },
  };

  const c1 = clone(o, true);

  console.log(c1, o);

  console.log(c1 === o, c1.e === o.e, c1.g === o.g, c1.h === o.h);

  const c2 = clone(o, true);
  console.log(c1 === c2, c2 === o);
</script>
